import { useCall } from '@/components';
import { isEqualStrictDeep } from '@/utils';
import { Table } from 'antd';
import React, { memo } from 'react';
import { DndProvider, DragSource, DropTarget } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';

let draggingIndex = -1;

function BodyRow(props) {
  const { isOver, connectDragSource, connectDropTarget, moveRow, ...restProps } = props;
  const style = { ...restProps.style, cursor: 'move' };

  let { className } = restProps;
  if (isOver) {
    if (restProps.index > draggingIndex) {
      className += ' drop-over-downward';
    }
    if (restProps.index < draggingIndex) {
      className += ' drop-over-upward';
    }
  }

  return connectDragSource(connectDropTarget(<tr {...restProps} className={className} style={style} />));
}

const rowSource = {
  beginDrag(props) {
    draggingIndex = props.index;
    return {
      index: props.index,
    };
  },
};

const rowTarget = {
  drop(props, monitor) {
    const dragIndex = monitor.getItem().index;
    const hoverIndex = props.index;

    // Don't replace items with themselves
    if (dragIndex === hoverIndex) {
      return;
    }

    // Time to actually perform the action
    props.moveRow(dragIndex, hoverIndex);

    // Note: we're mutating the monitor item here!
    // Generally it's better to avoid mutations,
    // but it's good here for the sake of performance
    // to avoid expensive index searches.
    monitor.getItem().index = hoverIndex;
  },
};

const DraggableBodyRow = DropTarget('row', rowTarget, (connect, monitor) => ({
  connectDropTarget: connect.dropTarget(),
  isOver: monitor.isOver(),
}))(
  DragSource('row', rowSource, (connect) => ({
    connectDragSource: connect.dragSource(),
  }))(BodyRow),
);

const sortComponents = {
  body: {
    row: DraggableBodyRow,
  },
};
SortTable = memo(SortTable, isEqualStrictDeep);

function SortTable({ onSort, ...props }) {
  return (
    <DndProvider backend={HTML5Backend}>
      <Table
        pagination={false}
        showHeader={false}
        {...props}
        components={sortComponents}
        onRow={useCall((record, index) => ({
          ...(props.onRow?.(record, index) ?? null),
          index,
          moveRow: onSort,
        }))}
      />
    </DndProvider>
  );
}

export default SortTable;
